home *** CD-ROM | disk | FTP | other *** search
/ NeXT Education Software Sampler 1992 Fall / NeXT Education Software Sampler 1992 Fall.iso / Programming / Source / WAIS / ir / irfileio.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-02-02  |  17.8 KB  |  789 lines

  1. /* WIDE AREA INFORMATION SERVER SOFTWARE:
  2.    No guarantees or restrictions.  See the readme file for the full standard
  3.    disclaimer.
  4.  
  5.    Brewster@think.com
  6. */
  7.  
  8. /********************************************************
  9.  *  Writing and reading structures to files.        *
  10.  *                            *
  11.  *  These use the Lisp printer format with the        *
  12.  *  lisp naming conventions.  You ask: "Why would    *
  13.  *  you want to use that?".  Well, we need an        *
  14.  *  easily readable data syntax that can handle        *
  15.  *  a large number of different data types.        *
  16.  *  Further, we need it to be tagged so that        *
  17.  *  run time tagged languages can read it and         *
  18.  *  it is flexible.  We need one that supports        *
  19.  *  optional fields so that the format can         *
  20.  *  grow backcompatibly.  And (the kicker),        *
  21.  *  it must be read from many languages since        *
  22.  *  user interfaces may be written in anything        *
  23.  *  from smalltalk to hypercard.            *
  24.  *                             *
  25.  *  -brewster 5/10/90                    *
  26.  ********************************************************/
  27.  
  28. #include <string.h>
  29. #include <ctype.h>
  30. #include "irfileio.h"
  31. #include "cutil.h"
  32.  
  33. #define INDENT_SPACES 2
  34. #define MAX_INDENT 40
  35. static long indent_level;  /* this is the number of indent levels */
  36.  
  37.  
  38. /**********************/
  39. /*  WRITING TO FILES  */
  40. /**********************/
  41.  
  42.  
  43. static void indent _AP((FILE* file));
  44.  
  45. static void indent(file)
  46. FILE* file;
  47. /* indent the right number of spaces.  make sure that indent_level is 
  48.  * non-negative, and that it does not indent too much
  49.  */
  50. {
  51.   long i;
  52.   for(i = 0; i <= MIN(MAX_INDENT, MAX(0L, indent_level * INDENT_SPACES)); i++){
  53.     putc(' ', file);
  54.   }
  55. }
  56.  
  57. long WriteStartOfList(file)
  58. FILE* file;
  59. {
  60.   indent_level++;
  61.   return(fprintf(file, " ( "));
  62. }
  63.  
  64. long WriteEndOfList(file)
  65. FILE* file;
  66. {
  67.   indent_level--;
  68.   return(fprintf(file, " ) "));
  69. }
  70.  
  71. long WriteStartOfStruct(name,file)
  72. char* name;
  73. FILE* file;
  74. {
  75.   indent_level++;
  76.   return(fprintf(file, " (:%s ", name));
  77. }
  78.  
  79. long WriteEndOfStruct(file)
  80. FILE* file;
  81. {
  82.   indent_level--;
  83.   return(fprintf(file, " ) "));
  84. }
  85.  
  86. long WriteSymbol(name,file)
  87. char* name;
  88. FILE* file;
  89. {
  90.   return(fprintf(file, " %s ", name));
  91. }
  92.  
  93. long WriteNewline(file)
  94. FILE* file;
  95. {
  96.   long return_value = fprintf(file, "\n");
  97.   indent(file);
  98.   return(return_value);
  99. }
  100.  
  101. long WriteLong(number,file)
  102. long number;
  103. FILE* file;
  104. {
  105.   return(fprintf(file, " %ld ", number));  
  106. }
  107.  
  108. long WriteDouble(number,file)
  109. double number;
  110. FILE* file;
  111. {
  112.   return(fprintf(file, " %f ", number));
  113. }
  114.  
  115. long WriteString(string,file)
  116. char* string;
  117. FILE* file;
  118. {
  119.   long i;
  120.   putc('\"', file);
  121.   for(i = 0; i < strlen(string); i++){
  122.     if(string[i] == '\"')
  123.       putc('\\', file);        /* quote the string quotes going into the file */
  124.     putc(string[i], file);
  125.   }
  126.   putc('\"', file);
  127.   return(1);
  128. }
  129.  
  130. long WriteAny(value,file)
  131. any* value;
  132. FILE* file;
  133. {
  134.   WriteStartOfStruct("any", file);
  135.   WriteSymbol(":size", file); WriteLong(value->size, file);
  136.   WriteSymbol(":bytes", file);
  137.   Write8BitArray(value->size, value->bytes, file);
  138.   return(WriteEndOfStruct(file));
  139. }
  140.  
  141. long Write8BitArray(length,array,file)
  142. long length;
  143. char* array;
  144. FILE* file;
  145. {
  146.   long i;
  147.   fprintf(file, " #( ");
  148.   for(i=0; i<length; i++){
  149.     WriteLong((long)array[i], file);
  150.   }
  151.   return(fprintf(file, " ) "));
  152. }
  153.  
  154.  
  155.  
  156.  
  157. /* Writes a time object to a file */
  158. long WriteTM(time,file)
  159. struct tm* time;
  160. FILE* file;
  161. {
  162.   WriteStartOfStruct("tm", file);
  163.   WriteSymbol(":tm-sec", file); WriteLong(time->tm_sec, file);
  164.   WriteSymbol(":tm-min", file); WriteLong(time->tm_min, file);
  165.   WriteSymbol(":tm-hour", file); WriteLong(time->tm_hour, file);
  166.   WriteSymbol(":tm-mday", file); WriteLong(time->tm_mday, file);
  167.   WriteSymbol(":tm-mon", file); WriteLong(time->tm_mon, file);
  168.   WriteNewline(file);
  169.   WriteSymbol(":tm-year", file); WriteLong(time->tm_year, file);
  170.   WriteSymbol(":tm-wday", file); WriteLong(time->tm_wday, file);
  171.   WriteNewline(file);
  172.   WriteSymbol(":tm-yday", file); WriteLong(time->tm_yday, file);
  173.   WriteSymbol(":tm-isdst", file); WriteLong(time->tm_isdst, file);
  174.   WriteEndOfStruct(file);
  175.   return(WriteNewline(file));
  176. };
  177.  
  178. Boolean  
  179. writeAbsoluteTime(time,file)
  180. struct tm* time;
  181. FILE* file;
  182. {
  183.   WriteStartOfStruct("absolute-time",file);
  184.   WriteNewline(file);
  185.   WriteSymbol(":year",file); WriteLong((long)time->tm_year,file);
  186.   WriteNewline(file);
  187.   WriteSymbol(":month",file); WriteLong((long)time->tm_mon,file);
  188.   WriteNewline(file);
  189.   WriteSymbol(":mday",file); WriteLong((long)time->tm_mday,file);
  190.   WriteNewline(file);
  191.   WriteSymbol(":hour",file); WriteLong((long)time->tm_hour,file);
  192.   WriteNewline(file);
  193.   WriteSymbol(":minute",file); WriteLong((long)time->tm_min,file);
  194.   WriteNewline(file);
  195.   WriteSymbol(":second",file); WriteLong((long)time->tm_sec,file);
  196.   WriteNewline(file);
  197.   return(WriteEndOfStruct(file));
  198. }
  199.  
  200.  
  201.  
  202.  
  203. /************************/
  204. /*  READING FROM FILES  */
  205. /************************/
  206.  
  207.  
  208. /* these are states of the parser */
  209. #define BEFORE 1
  210. #define DURING 2
  211. #define HASH 3
  212. #define S 4
  213. #define QUOTE 5
  214.  
  215. /* returns TRUE if it hits an '(' before hitting any non whitespace.
  216.    It has an added hack to detect NIL: it looks to make sure that it is nil,
  217.    and then ungetc's a \) on the stream so that the end-checkers will catch it.
  218.    Quack. */
  219. Boolean ReadStartOfList(file)
  220. FILE* file;
  221. {
  222.   char ch;
  223.   while(TRUE){
  224.     ch = getc(file);
  225.     if(ch == '(') 
  226.       return(TRUE);
  227.     if(!isspace(ch)){
  228.       /* check for NIL */
  229.       if(ch == 'N' || ch == 'n'){
  230.     ch = getc(file);
  231.     if(ch == 'I' || ch == 'i'){
  232.       ch = getc(file);
  233.       if(ch == 'L' || ch == 'l'){
  234.         ungetc(')', file);
  235.         return(TRUE);
  236.       }
  237.     }
  238.       }
  239.       return(FALSE); /* not NIL */
  240.     }
  241.   }
  242. }
  243.  
  244.  
  245. /* returns TRUE if it hits an ')' before hitting any non whitespace*/
  246. Boolean ReadEndOfList(file)
  247. FILE* file;
  248. {
  249.   char ch;
  250.   while(TRUE){
  251.     ch = getc(file);
  252.     if(ch == ')') 
  253.       return(TRUE);
  254.     if(!isspace(ch)) 
  255.       return(FALSE);
  256.   }
  257. }
  258.  
  259. #define STRING_ESC '\\'
  260.  
  261. long 
  262. SkipObject(file)
  263. FILE* file;
  264. /* read an object of unknown type out of the file.  We handle:
  265.       strings
  266.       longs, doubles, and symbols
  267.       structs, lists, and arrays
  268.    and anything composed of them (absolute time etc)
  269. */
  270. {
  271.   long ch;
  272.  
  273.   while (true)    
  274.     { ch = getc(file);
  275.       if (ch == EOF)
  276.     break; /* we are done */
  277.       else
  278.     { if (isspace(ch))
  279.         continue; /* skip this char */
  280.       else if (ch == '"') /* string */
  281.         { long escapeCount = 0;
  282.           while (true)
  283.         { ch = getc(file);
  284.           if (ch == EOF)
  285.             break;
  286.           else
  287.             { if (ch == STRING_ESC)
  288.             { escapeCount++;
  289.               escapeCount = escapeCount % 2;
  290.             }
  291.               if (ch == '"' && escapeCount == 0)
  292.             break; /* out of reading string */
  293.                     }
  294.         }
  295.           break; /* we are done */
  296.             }
  297.       else if ((isdigit(ch) || ch == '-' || ch == '.') || /* number */
  298.            (ch == ':')) /* symbol */
  299.         { while (!isspace(ch)) /* just read till there is white space */
  300.         { ch = getc(file);
  301.           if (ch == EOF)
  302.             break;
  303.         }
  304.           break; /* we are done */
  305.         }
  306.       else if ((ch == '#') || /* array */
  307.            (ch == '(')) /* struct or list */
  308.         { long parenCount = 1;
  309.           if (ch == '#')    
  310.         ch = getc(file); /* read in the '(' so we can think of it
  311.                     as a list */
  312.           while (parenCount > 0)
  313.         { ch = getc(file);
  314.           if (ch == EOF)
  315.             break;
  316.           else if (ch == '"')
  317.             { /* start of a string, it may contain parens, 
  318.              so we will have to skip it */
  319.               ungetc(ch,file);
  320.               SkipObject(file);
  321.             }
  322.           else if (ch == '(') /* entering a new structure */    
  323.             parenCount++;
  324.           else if (ch == ')') /* leaving a structure */
  325.             parenCount--;
  326.         }
  327.           break; /* we are done */
  328.         }
  329.     }
  330.     }
  331.  
  332.   return(true);
  333. }
  334.  
  335. long ReadLong(file,answer)
  336. FILE* file;
  337. long* answer;
  338. /* reads a long int a file returns true if successful, false otherwise */
  339. {
  340.   char ch;
  341.   long state = BEFORE;
  342.   boolean isNegative = false;
  343.   long count = 0;
  344.   
  345.   *answer = 0;
  346.   
  347.   while(TRUE){
  348.     ch = getc(file);
  349.     if (ch == EOF){
  350.       break;            /* we are done */
  351.     }
  352.     else if (isdigit(ch)){
  353.       if(state == BEFORE){
  354.     state = DURING;
  355.       }
  356.       count++;
  357.       if(count == 12){
  358.     /* then we have an error in the file, 32 bit numbers can not be more
  359.        than 10 digits long */
  360.     return(false);
  361.       }
  362.       *answer = *answer * 10 + (ch - '0');
  363.     }
  364.     else if (ch == '-') {
  365.       if (isNegative)
  366.     /* then we have an error since there should be only one - in a number */
  367.     return(false);
  368.       if (state == BEFORE) {
  369.     /* we are ok since the - must come before any digits */
  370.     isNegative = true;
  371.     state = DURING;
  372.       }
  373.       else {
  374.     ungetc(ch,file);
  375.     break;            /* we are done */
  376.       }
  377.     }
  378.     else if(ch == ')' && (state == DURING)){
  379.       ungetc(ch, file);
  380.       return(true);        /* we are done */
  381.     }
  382.     else if(!isspace(ch)){
  383.       /* then we have an error since it should be a digit or a space */
  384.       return(false);
  385.     }
  386.     /* we do not have an digit */
  387.     else if(state == DURING){
  388.       ungetc(ch, file);
  389.       break;            /* we are done */
  390.     }
  391.     /* otherwise we are still before the start */
  392.   }
  393.   
  394.   if (isNegative)
  395.     *answer *= -1;
  396.   return(true);
  397. }
  398.  
  399. long ReadDouble(file,answer)
  400. FILE* file;
  401. double* answer;
  402. {
  403.   /* XXX this routine needs to deal with negative numbers! */
  404.   char ch;
  405.   long state = BEFORE;
  406.   long count = 0;
  407.   long decimal_count = 0;
  408.   
  409.   *answer = 0.0;
  410.   
  411.   while(TRUE){    
  412.     ch = getc(file);
  413.     if (ch == EOF){
  414.       return(true);
  415.     }
  416.     else if (ch == '.'){
  417.       decimal_count ++;
  418.     }
  419.     else if (isdigit(ch)){
  420.       if(state == BEFORE){
  421.     state = DURING;
  422.       }
  423.       count++;
  424.       if(count == 12){
  425.     /* then we have an error in the file, 32 bit numbers can not be more
  426.        than 10 digits long */
  427.     return(false);
  428.       }
  429.       if (decimal_count == 0){
  430.     *answer = *answer * 10 + (ch - '0');
  431.       }
  432.       else{            /* then we are in the fraction part */
  433.     double fraction = (ch - '0');
  434.     long internal_count;
  435.     for(internal_count = 0; internal_count < decimal_count; 
  436.         internal_count++){
  437.       fraction = fraction / 10.0;
  438.     }
  439.     *answer = *answer + fraction;
  440.     decimal_count++;
  441.       }
  442.     }
  443.     else if(!isspace(ch)){
  444.       /* then we have an error since it should be a digit or a space */
  445.       return(false);
  446.     }
  447.     /* we do not have an digit */
  448.     else if(state == DURING){
  449.       ungetc(ch, file);
  450.       return(true);        /* we are done */
  451.     }
  452.     /* otherwise we are still before the start */
  453.   }
  454. }
  455.  
  456. static Boolean issymbolchar _AP((long ch));
  457.  
  458. static 
  459. Boolean issymbolchar(ch)
  460. long ch;
  461. /* reads a symbol from a file and put it in the string argument.
  462.  * The string_size argument is used to make sure the string is not 
  463.  * overflowed.
  464.  */
  465. {
  466.   return(!( isspace(ch) || ch == ')' || ch == '(' || ch == EOF));
  467. }
  468.  
  469. /* reads a symbol from a file */
  470. long ReadSymbol(string,file,string_size)
  471. char* string;
  472. FILE* file;
  473. long string_size;
  474. {
  475.   char ch;
  476.   long state = BEFORE;
  477.   long position = 0;
  478.   
  479.   while(TRUE){
  480.     ch = getc(file);
  481.     if((state == BEFORE) && (ch == ')'))
  482.       return(END_OF_STRUCT_OR_LIST);
  483.     if(issymbolchar((long)ch)){    /* we are in a symbol */
  484.       if(state == BEFORE)
  485.     state = DURING;
  486.       string[position] = ch;
  487.       position++;
  488.       if(position >= string_size){
  489.     string[string_size - 1] = '\0';
  490.     return(FALSE);
  491.       }
  492.     }
  493.     /* we do not have an symbol character. we are done */
  494.     else if((state == DURING) || ch == EOF){
  495.       if(ch != EOF) ungetc(ch, file);
  496.       string[position] = '\0';
  497.       return(TRUE);        /* we are done */
  498.     }
  499.     /* otherwise we are still before the start of the symbol */
  500.   }
  501. }
  502.  
  503. long ReadEndOfListOrStruct(file)
  504. FILE* file;
  505. {
  506.   char ch;
  507.   while(TRUE){
  508.     ch = getc(file);
  509.     if (EOF == ch) 
  510.       return(FALSE);
  511.     else if(')' == ch) 
  512.       return(TRUE);
  513.     else if(!isspace(ch)) 
  514.       return(FALSE);
  515.   }
  516. }
  517.  
  518. /* reads a string from a file */
  519. long ReadString(string,file,string_size)
  520. char* string;
  521. FILE* file;
  522. long string_size;
  523. {
  524.   char ch;
  525.   long state = BEFORE;
  526.   long position = 0;
  527.   string[0] = '\0';  /* initialize to nothing */
  528.   
  529.   while(TRUE){
  530.     ch = getc(file);
  531.     if((state == BEFORE) && (ch == '\"'))
  532.       state = DURING;
  533.     else if (EOF == ch){
  534.       string[position] = '\0';
  535.       return(FALSE);
  536.     }
  537.     else if ((state == BEFORE) && (ch == ')'))
  538.       return(END_OF_STRUCT_OR_LIST);
  539.     else if ((state == DURING) && (ch == '\\'))
  540.       state = QUOTE; /* do nothing */
  541.     else if ((state == DURING) && (ch == '"')){    
  542.       string[position] = '\0';
  543.       return(TRUE);
  544.     }
  545.     else if ((state == QUOTE) || (state == DURING)){
  546.             if(state == QUOTE)
  547.                 state = DURING;
  548.             string[position] = ch;
  549.             position++;
  550.             if(position >= string_size){
  551.                 string[string_size - 1] = '\0';
  552.                 return(FALSE);
  553.             }
  554.         }
  555.         /* otherwise we are still before the start of the string */
  556.     }
  557. }
  558.  
  559. /* returns TRUE if it is the start of a struct
  560.  * returns END_OF_STRUCT_OR_LIST if it is a ')'
  561.  * returns FALSE if it is something unexpected
  562.  */
  563. long ReadStartOfStruct(name,file)
  564. char* name;
  565. FILE* file;
  566. {
  567.   char ch;
  568.   long state = BEFORE;
  569.     
  570.   name[0] = '\0';
  571.     
  572.   while(TRUE){
  573.     ch = getc(file);
  574.     if((state == BEFORE) && (ch == '#'))
  575.       state = HASH;
  576.     if((state == BEFORE) && (ch == '('))
  577.       state = DURING;
  578.     else if((state == BEFORE) && (ch == ')'))
  579.       return(END_OF_STRUCT_OR_LIST);
  580.     else if((state == BEFORE) && !isspace(ch))
  581.       return(FALSE);        /* we have a problem */
  582.     else if(state == HASH){
  583.       if (ch == 's')
  584.     state = S;
  585.       else{
  586.     fprintf(stderr,"Expected an 's' but got an %c\n", ch);
  587.     return(FALSE);
  588.       }
  589.     }
  590.     else if(state == S){
  591.       if (ch == '(')
  592.     state = DURING;
  593.       else{
  594.     fprintf(stderr,"Expected an '(' but got an an %c\n",ch);
  595.     return(FALSE);
  596.       }
  597.     }
  598.     else if(state == DURING){
  599.       return(ReadSymbol(name, file, MAX_SYMBOL_SIZE));
  600.     }
  601.   }
  602. }
  603.  
  604. /* returns TRUE if it is the right start of a struct,
  605.  * returns END_OF_STRUCT_OR_LIST if it is the end of a list,
  606.  * returns FALSE if it is something weird
  607.  */
  608. long CheckStartOfStruct(name,file)
  609. char* name;
  610. FILE* file;
  611. {
  612.   char temp_string[MAX_SYMBOL_SIZE];
  613.   long result = ReadStartOfStruct(temp_string, file);
  614.   if(result == END_OF_STRUCT_OR_LIST)
  615.     return(END_OF_STRUCT_OR_LIST);
  616.   else if(result == FALSE)
  617.     return(FALSE);
  618.   else if(0 == strcmp(temp_string, name))
  619.     return(TRUE);
  620.   else 
  621.     return(FALSE);
  622. }
  623.  
  624. /* reads an any.  an any with no bytes allocated.  The right number of bytes
  625.  * will be malloc'ed while reading
  626.  */
  627. long ReadAny(destination,file)
  628. any* destination;
  629. FILE* file;
  630. {
  631.   char temp_string[MAX_SYMBOL_SIZE];
  632.     
  633.   destination->size = 0; /* initialize so that if an error happens 
  634.                 it does not blow up */
  635.   if(FALSE == CheckStartOfStruct("any", file)){
  636.     fprintf(stderr,"An 'any' structure was not read from the disk");
  637.     return(FALSE);
  638.   }
  639.     
  640.   while(TRUE){
  641.     long check_result;
  642.     check_result = ReadSymbol(temp_string, file, MAX_SYMBOL_SIZE);
  643.     if(FALSE == check_result) 
  644.       return(FALSE);
  645.     if(END_OF_STRUCT_OR_LIST == check_result) 
  646.       return(TRUE);
  647.         
  648.     if(0 == strcmp(temp_string, ":size")) {
  649.       long    size;
  650.       ReadLong(file,&size);
  651.       destination->size = (unsigned long)size;
  652.     }
  653.     else if(0 == strcmp(temp_string, ":bytes")){
  654.       long result;
  655.       /* the size must have been read in by now */
  656.       destination->bytes = (char*)s_malloc(destination->size);
  657.       if(NULL == destination->bytes){
  658.     fprintf(stderr,
  659.         "Error on reading file. Malloc ran out of memory in an ANY");
  660.     return(FALSE);
  661.       }
  662.       result = Read8BitArray(destination->bytes, file, destination->size);
  663.       if(FALSE == result)
  664.     return(FALSE);
  665.     }
  666.     else{
  667.       fprintf(stderr,"Unknown keyword for ANY %s\n", temp_string);
  668.       return(FALSE);
  669.     }
  670.   }
  671. }
  672.  
  673. /* this does not need the length, but it will probably know it in all cases */
  674. long Read8BitArray(destination,file,length)
  675. char* destination;
  676. FILE* file;
  677. long length;
  678. {
  679.   /* arrays start with #( */
  680.   char ch;
  681.   long state = BEFORE;
  682.   while(TRUE){
  683.     ch = getc(file);
  684.     if((state == BEFORE) && ((ch == '#') || (ch == '('))) {
  685.       if (ch == '(') state = DURING;
  686.       else state = HASH;
  687.     }
  688.     else if((state == BEFORE) && !isspace(ch)){
  689.       fprintf(stderr,"error in reading array.  Expected # and got %c", ch);
  690.       return(FALSE);
  691.     }
  692.     else if(state == HASH){
  693.       if (ch == '(')
  694.     state = DURING;
  695.       else{
  696.     fprintf(stderr,"Expected an '(' but got an %c\n", ch);
  697.     return(FALSE);
  698.       }
  699.     }
  700.     else if(state == DURING){
  701.       long i;
  702.       ungetc(ch, file);
  703.       for(i = 0; i < length; i++){
  704.     long value;
  705.     if(ReadLong(file,&value) == false){ /* then it error'ed */
  706.       fprintf(stderr,"Error in reading a number from the file.");
  707.       return(FALSE);
  708.     }
  709.     if(value > 255){    /* then we have read a non-char */
  710.       fprintf(stderr,"Error in reading file.  Expected a byte in an ANY, but got %ld", value);
  711.       return(FALSE);
  712.     }
  713.     destination[i] = (char)value;
  714.       }
  715.       if(FALSE == ReadEndOfListOrStruct(file)){
  716.     fprintf(stderr,"array was wrong length");
  717.     return(FALSE);
  718.       }
  719.       return(TRUE);
  720.     }
  721.   }
  722. }
  723.             
  724.  
  725. Boolean
  726. readAbsoluteTime(time,file)
  727. struct tm* time;
  728. FILE* file;
  729. {
  730.   if (CheckStartOfStruct("absolute-time",file) == FALSE)
  731.     return(false);
  732.           
  733.   while (true)
  734.     { long result;
  735.       long val;
  736.       char temp_string[MAX_SYMBOL_SIZE + 1];
  737.      
  738.       result = ReadSymbol(temp_string,file,MAX_SYMBOL_SIZE);
  739.      
  740.       if (result == END_OF_STRUCT_OR_LIST)
  741.     break;
  742.       else if (result == false)
  743.     return(false);
  744.                   
  745.       if (strcmp(temp_string,":second") == 0)
  746.     { if (ReadLong(file,&val) == false)
  747.         return(false);
  748.       time->tm_sec = val;
  749.     }
  750.  
  751.       else if (strcmp(temp_string,":minute") == 0)
  752.     { if (ReadLong(file,&val) == false)
  753.         return(false);
  754.       time->tm_min = val;
  755.     }
  756.  
  757.       else if (strcmp(temp_string,":hour") == 0)
  758.     { if (ReadLong(file,&val) == false)
  759.         return(false);
  760.       time->tm_hour = val;
  761.     }
  762.  
  763.       else if (strcmp(temp_string,":mday") == 0)
  764.     { if (ReadLong(file,&val) == false)
  765.         return(false);
  766.       time->tm_mday = val;
  767.     }
  768.  
  769.       else if (strcmp(temp_string,":month") == 0)
  770.     { if (ReadLong(file,&val) == false)
  771.         return(false);
  772.       time->tm_mon = val;
  773.     }
  774.  
  775.       else if (strcmp(temp_string,":year") == 0)
  776.     { if (ReadLong(file,&val) == false)
  777.         return(false);
  778.       time->tm_year = val;
  779.     }
  780.       
  781.       else
  782.     SkipObject(file);
  783.  
  784.     }
  785.  
  786.   return(true);
  787. }
  788.  
  789.